<?php

declare(strict_types=1);

namespace wym\addons;

use Exception;
use think\App;
use think\facade\Config;
use think\facade\View;
use think\Request;

abstract class Addons
{
    // app 容器
    protected App $app;

    // 请求对象
    protected Request $request;

    // 当前插件标识
    protected mixed $name;

    // 插件路径
    protected string $addon_path;

    // 视图模型
    protected $view;

    // 插件配置
    protected string $addon_config;

    // 插件信息
    protected string $addon_info;

    /**
     * 插件构造函数
     * Addons constructor.
     *
     * @param App $app
     */
    public function __construct(App $app)
    {
        $this->app          = $app;
        $this->request      = $app->request;
        $this->name         = $this->getName();
        $this->addon_path   = $app->addons->getAddonsPath() . $this->name . DS;
        $this->addon_config = "addon_{$this->name}_config";
        $this->addon_info   = "addon_{$this->name}_info";
        $this->view         = clone View::engine('Think');
        $this->view->config([
            'view_path' => $this->addon_path . 'view' . DS,
        ]);

        // 控制器初始化
        $this->initialize();
    }

    // 初始化
    protected function initialize() {}

    /**
     * 获取插件标识
     *
     * @return string
     */
    final protected function getName(): string
    {
        $class = get_class($this);
        [, $name] = explode('\\', $class);
        $this->request->addon = $name;

        return $name;
    }

    /**
     * 加载模板输出
     *
     * @param string $template
     * @param array  $vars 模板文件名
     *
     * @return string 模板输出变量
     * @throws Exception
     */
    protected function fetch(string $template = '', array $vars = []): string
    {
        return $this->view->fetch($template, $vars);
    }

    /**
     * 渲染内容输出
     *
     * @access protected
     *
     * @param string $content 模板内容
     * @param array  $vars    模板输出变量
     *
     * @return string
     */
    protected function display(string $content = '', array $vars = []): string
    {
        return $this->view->display($content, $vars);
    }

    /**
     * 模板变量赋值
     *
     * @access protected
     *
     * @param mixed  $name  要显示的模板变量
     * @param string $value 变量的值
     *
     * @return $this
     */
    protected function assign(mixed $name, string $value = ''): static
    {
        $this->view->assign([$name => $value]);

        return $this;
    }

    /**
     * 初始化模板引擎
     *
     * @access protected
     *
     * @param array|string $engine 引擎参数
     *
     * @return $this
     */
    protected function engine(array|string $engine): static
    {
        $this->view->engine($engine);

        return $this;
    }

    /**
     * 插件基础信息
     *
     * @return array
     */
    final public function getInfo(): array
    {
        $info = config($this->addon_info, []);

        if ($info) {
            return $info;
        }
        // 文件属性
        $info = $this->info ?? [];
        // 文件配置
        $info_file = $this->addon_path . 'plugin.ini';

        if (is_file($info_file)) {
            $_info = parse_ini_file($info_file, true, INI_SCANNER_TYPED) ?: [];
            $info  = array_merge($info, $_info);
        }
        Config::set($info, $this->addon_info);

        return $info ?? [];
    }

    /**
     * 获取配置信息
     *
     * @param bool $type 是否获取完整配置
     *
     * @return array|mixed
     */
    final public function getConfig(bool $type = false): mixed
    {
        $config = Config::get($this->addon_config, []);

        if ($config) {
            return $config;
        }
        $config_file = $this->addon_path . 'config.php';

        if (is_file($config_file)) {
            $temp_arr = (array)include $config_file;

            if ($type) {
                return $temp_arr;
            }

            foreach ($temp_arr as $key => $value) {
                $config[$key] = $value['value'];
            }
            unset($temp_arr);
        }
        Config::set($config, $this->addon_config);

        return $config;
    }

    /**
     * 设置插件信息数据
     *
     * @param string $name
     * @param array  $value
     *
     * @return array
     */
    final public function setInfo(string $name = '', array $value = []): array
    {
        if (empty($name)) {
            $name = $this->getName();
        }
        $info = $this->getInfo();
        $info = array_merge($info, $value);
        Config::set($info, $name);

        return $info;
    }

    //必须实现安装插件方法
    abstract public function install();

    //必须实现卸载插件方法
    abstract public function uninstall();

    //必须实现升级插件方法
    abstract public function upgrade();

    //必须实现启用插件方法
    abstract public function enabled();

    //必须实现禁用插件方法
    abstract public function disabled();
}
